import math
import pyglet
from pyglet.gl import *
from random import randint
from operator import itemgetter

window = pyglet.window.Window()
window.width = 1200
pixelSize = 10
window.height = pixelSize

# Somehow, these idle functions need to be used to override Pyglet's idle function
# So that we stop firing the on_draw() event
def idle( self ):
    # An alternate idle loop than Pyglet's default.
    # don't call on_draw
    pyglet.clock.tick(poll=True)
    return pyglet.clock.get_sleep_time( sleep_idle = True )

def patch_idle_loop():
    # Replaces the default Pyglet idle look with the :py:func:`idle` function in this module.
    # check that the event loop has been over-ridden
    if pyglet.app.EventLoop.idle != idle:
        # over-ride the default event loop
        pyglet.app.EventLoop.idle = idle

@window.event
def on_draw():
	window.clear()
	colors = generate_colors()
	draw_pixels(colors)
	sourceColor = Color(0, 0, 255)
	sortedColors = sort_colors(colors, sourceColor)
	draw_pixels(sortedColors)

class Primitive(object):
	# "Stores a single list of vertices and a color"
	def __init__(self, verts, color, primtype=GL_TRIANGLE_FAN):
		self.verts = verts
		self.color = color
		self.primtype = primtype

	def offset(self, dx, dy):
		self.verts = [(v[0] + dx, v[1] + dy) for v in self.verts]
		return self

class Shape(object):
	# "A list of primitives"
	def __init__(self, items=None):
		self.primitives = []
		if items:
			self.add_items(items)

	def add_items(self, items):
		# "Add a list of primitives and shapes"
		for item in items:
			if isinstance(item, Shape):
				self.add_shape(item)
			else:
				self.primitives.append(item)

	def add_shape(self, other):
		# "Add the primitives from a given shape"
		for prim in other.primitives:
			self.primitives.append(prim)
			

def render(shape):
	for primitive in shape.primitives:
		glColor3ub(*primitive.color)
		glBegin(primitive.primtype)
		for vert in primitive.verts:
			glVertex2f(*vert)
		glEnd()
		

# Color class
class Color:
	def __init__(self, red=255, green=255, blue=255):
		self.red = red
		self.green = green
		self.blue=blue
	
	def rgb(self):
		return (self.red, self.green, self.blue)
	
	def rgba(self):
		return (self.red, self.green, self.blue, 255)


# Pixel Class, for size x size squares of color
class Pixel:
	def __init__(self, x=0, y=0, color=Color(255, 0, 0), size=4):
		self.x = x
		self.y = y
		self.color = color
		self.size = size
		self.verts = [ (x, y), (x, y+self.size), (x+self.size, y+self.size), (x+self.size, y) ]
		self.shape = Shape( [ Primitive(self.verts, self.color.rgb()) ] )
	
	def paint(self):
		render(self.shape)


# Utility method for generating a list of random colors
def generate_colors():
	num_colors = int(window.width / pixelSize)
	colors = list()
	
	for i in range(num_colors):
		r = randint(0, 255)
		g = randint(0, 255)
		b = randint(0, 255)
		colors.append(Color(r, g, b))
	
	return colors

# Sorts a list of colors according to distance from the source color
def sort_colors(colors, source):
	colorMap = []
	sortedColors = list()
	for i in range(len(colors)):
		dist = dist_3d(colors[i], source)
		colorMap.append((dist, colors[i]))
	
	sorted_by_dist = sorted(colorMap, key=lambda tup: tup[0])
	
	for (d, c) in sorted_by_dist:
		sortedColors.append(c)
	
	return sortedColors


def draw_pixels(colors):
	i = 0
	for x in xrange(0, window.width, pixelSize):
		p = Pixel(x, 0, colors[i], pixelSize)
		p.paint()
		i += 1


# Distance from a to b in 3 dimensional (r, g, b) space
def dist_3d(a, b):
	ar = a.red
	ag = a.green
	ab = a.blue
	br = b.red
	bg = b.green
	bb = b.blue
	rd = ar-br
	gd = ag-bg
	bd = ab-bb
	return int( math.sqrt(math.pow(rd, 2) + math.pow(gd, 2) + math.pow(bd, 2)) )

	
	
pyglet.app.run()

